using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using java.util;
using System.Threading;

namespace org.jawk.ext
{
	/// <summary>Enable Socket processing in Jawk.</summary>
	/// <remarks>
	/// Enable Socket processing in Jawk.
	/// <p>
	/// To use:
	/// <blockquote><pre>
	/// ## example echo server using CServerSocket (character-based)
	/// BEGIN {
	/// css = CServerSocket(7777);
	/// }
	/// $0 = SocketAcceptBlock(css,
	/// SocketInputBlock(handles,
	/// SocketCloseBlock(css, handles \
	/// )));
	/// $1 == "SocketAccept" {
	/// handles[SocketAccept($2)] = 1
	/// }
	/// $1 == "SocketClose" {
	/// SocketClose($2)
	/// delete handles[$2]
	/// }
	/// $1 == "SocketInput" {
	/// input = SocketRead($2)
	/// SocketWrite($2, input);	## do the echo
	/// }
	/// </pre></blockquote>
	/// <p>
	/// The extension functions are as follows:
	/// <ul>
	/// <hr>
	/// <li><strong><em><font size=+1>ServerSocket</font></em></strong> -<br />
	/// Sets up a server socket to listen for incomming
	/// connections.  SocketRead on sockets accepted
	/// by ServerSocket return arbitrary-length Strings
	/// (bytes buffered by the input stream, converted
	/// to a string).<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>port number - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string handle to a serversocket.
	/// </ul><p>
	/// <li><strong><em><font size=+1>CServerSocket</font></em></strong> -<br />
	/// Sets up a server socket to listen for incomming
	/// connections.  SocketRead on sockets accepted
	/// by CServerSocket return strings which terminate
	/// by a newline, or text in the input buffer just
	/// prior to the closing of the socket.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>port number - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string handle to a cserversocket.
	/// </ul><p>
	/// <hr>
	/// <li><strong><em><font size=+1>Socket</font></em></strong> -<br />
	/// Create a Socket and connect it to a TCP socket
	/// endpoint.  SocketRead on sockets returned
	/// by Socket return arbitrary-length Strings
	/// (bytes buffered by the input stream, converted
	/// to a string).<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>hostname/ip/"localhost" - required
	/// <li>port number - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string handle to a socket.
	/// </ul><p>
	/// <li><strong><em><font size=+1>CSocket</font></em></strong> -<br />
	/// Create a Socket and connect it to a TCP socket
	/// endpoint.  SocketRead on sockets returned
	/// by Socket return strings which terminate
	/// by a newline, or text in the input buffer just
	/// prior to the closing of the socket.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>hostname/ip/"localhost" - required
	/// <li>port number - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string handle to a csocket.
	/// </ul><p>
	/// <hr>
	/// <li><strong><em><font size=+1>SocketAcceptBlock</font></em></strong> -<br />
	/// Blocks until a serversocket or cserversocket
	/// is ready to accept a connecting socket.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>Any mix of
	/// serversocket or cserversocket handles
	/// and/or associative arrays whose keys
	/// are serversocket or cserversocket handles.
	/// The last argument can optionally be
	/// another block call for block chaining.
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string of the form:
	/// <code><font size=+1>SocketAccept<em>OFS</em>handle</font></code>
	/// where handle is a serversocket or cserversocket
	/// handle.
	/// </ul><p>
	/// <li><strong><em><font size=+1>SocketInputBlock</font></em></strong> -<br />
	/// Blocks until a socket or csocket is ready
	/// to accept input (via SocketRead).<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>Any mix of
	/// socket or csocket handles and/or associative
	/// arrays whose keys are socket or csocket handles.
	/// The last argument can optionally be
	/// another block call for block chaining.
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string of the form: <code><font size=+1>SocketInput<em>OFS</em>handle</font></code>
	/// where handle is a socket or csocket
	/// handle.
	/// </ul><p>
	/// <li><strong><em><font size=+1>SocketCloseBlock</font></em></strong> -<br />
	/// Blocks until a serversocket, cserversocket,
	/// socket, or csocket has been closed on the
	/// remote end.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>Any mix of
	/// serversocket, cserversocket, socket, or csocket
	/// handles and/or associative
	/// arrays whose keys are serversocket, cserversocket,
	/// socket, or csocket handles.
	/// The last argument can optionally be
	/// another block call for block chaining.
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string of the form: <code><font size=+1>SocketClose<em>OFS</em>handle</font></code>
	/// where handle is a serversocket, cserversocket, socket,
	/// or csocket handle.
	/// </ul><p>
	/// <hr>
	/// <li><strong><em><font size=+1>SocketAccept</font></em></strong> -<br />
	/// Accepts a socket from a serversocket or
	/// a cserversocket.  The operation will
	/// block if there is no socket to accept.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>serversocket-or-cserversocket handle - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string handle to a socket or csocket.
	/// </ul><p>
	/// <hr>
	/// <li><strong><em><font size=+1>SocketRead</font></em></strong> -<br />
	/// Reads input from the input stream of a socket
	/// or a csocket.  For a socket, the input length
	/// is arbitrary.  For a csocket, the input
	/// length is bounded by a newline or upon
	/// termination of the socket.
	/// The operation will block if there is no input
	/// on the socket.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>socket-or-csocket handle - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>A string containing the input on the socket.
	/// </ul><p>
	/// <li><strong><em><font size=+1>SocketWrite</font></em></strong> -<br />
	/// Writes data to the socket or csocket.
	/// For a socket, the string is converted
	/// to bytes (via java.lang.String.getBytes()),
	/// and the bytes are sent to the socket's
	/// output stream.
	/// For a csocket, println() is called on the
	/// underlying socket's PrintStream.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>socket-or-csocket handle - required
	/// <li>msg - required - The string to write to
	/// the socket.  For a csocket, a newline
	/// is added to it (via the
	/// java.io.PrintStream.println() method).
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>1 upon a successful write, 0 otherwise
	/// </ul><p>
	/// <li><strong><em><font size=+1>SocketFlush</font></em></strong> -<br />
	/// Flushes the output stream of a socket or csocket.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>socket-or-csocket handle - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>1 upon a successful flush, 0 otherwise
	/// </ul><p>
	/// <hr>
	/// <li><strong><em><font size=+1>SocketClose</font></em></strong> -<br />
	/// Closes the socket/csocket on the local end,
	/// or a serversocket/cserversocket.
	/// Can be called in response to a SocketCloseBlock
	/// event, or to force a socket/csocket connection to
	/// terminate.<br />
	/// <strong>Parameters:</strong>
	/// <ul>
	/// <li>socket/csocket/serversocket/cserversocket handle - required
	/// </ul>
	/// <strong>Returns:</strong>
	/// <ul>
	/// <li>1 upon successful close, 0 otherwise
	/// </ul><p>
	/// <hr>
	/// </ul>
	/// </remarks>
	public class SocketExtension : org.jawk.ext.AbstractExtension
	{
		/// <summary>
		/// Either threaded or non-threaded (nio-style) socket
		/// handling.
		/// </summary>
		/// <remarks>
		/// Either threaded or non-threaded (nio-style) socket
		/// handling.  The threaded implementation is provided
		/// upon initial release. Non-threaded
		/// functionality will be available in a subsequent
		/// release.
		/// </remarks>
		private org.jawk.ext.IIO_Style impl_delegate;

		public sealed override void Init(org.jawk.jrt.IVariableManager vm, org.jawk.jrt.JRT
			 jrt)
		{
			base.Init(vm, jrt);
			impl_delegate = new org.jawk.ext.Threaded_IO_Style(vm);
		}

		public sealed override string GetExtensionName()
		{
			return "Socket Support";
		}

		public sealed override string[] ExtensionKeywords()
		{
			return new string[] { "ServerSocket", "CServerSocket", "Socket", "CSocket", "SocketAcceptBlock"
				, "SocketInputBlock", "SocketCloseBlock", "SocketAccept", "SocketRead", "SocketWrite"
				, "SocketFlush", "SocketClose" };
		}

		// i.e., ss = ServerSocket(8080) or ss = ServerSocket("ip", 8080)
		// i.e., css = CServerSocket(8080) or css = CServerSocket("ip", 8080)
		// i.e., s = Socket("localhost", 8080)
		// i.e., cs = CSocket("localhost", 8080)
		// i.e., $0 = SocketAcceptBlock(ss, css,
		// i.e.,	SocketInputBlock(s, cs,
		// i.e.,	  SocketCloseBlock(ss,css, s,cs)));
		// i.e., cs = SocketAccept(css)
		// i.e., buf = SocketRead(s) or line = SocketRead(cs)
		// i.e., SocketWrite(s, "hi there\n") or SocketWrite(cs, "hi there")
		// i.e., SocketFlush(s) or SocketFlush(cs)
		// i.e., SocketClose(ss) or SocketClose(cs)
		public sealed override object Invoke(string method_name, object[] args)
		{
				if (method_name.Equals("ServerSocket"))
				{
					if (args.Length == 1)
					{
						return impl_delegate.Serversocket(null, (int)org.jawk.jrt.JRT.ToDouble(args[0]));
					}
					else
					{
						if (args.Length == 2)
						{
							return impl_delegate.Serversocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble
								(args[1]));
						}
						else
						{
							throw new org.jawk.jrt.IllegalAwkArgumentException("Expecting 1 or 2 arguments, not "
								 + args.Length);
						}
					}
				}
				else
				{
					if (method_name.Equals("CServerSocket"))
					{
						if (args.Length == 1)
						{
							return impl_delegate.Cserversocket(null, (int)org.jawk.jrt.JRT.ToDouble(args[0]));
						}
						else
						{
							if (args.Length == 2)
							{
								return impl_delegate.Cserversocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble
									(args[1]));
							}
							else
							{
								throw new org.jawk.jrt.IllegalAwkArgumentException("Expecting 1 or 2 arguments, not "
									 + args.Length);
							}
						}
					}
					else
					{
						if (method_name.Equals("Socket"))
						{
							CheckNumArgs(args, 2);
							return impl_delegate.Socket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble(
								args[1]));
						}
						else
						{
							if (method_name.Equals("CSocket"))
							{
								CheckNumArgs(args, 2);
								return impl_delegate.Csocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble
									(args[1]));
							}
							else
							{
								if (method_name.Equals("SocketAcceptBlock"))
								{
									return impl_delegate.Socketacceptblock(args);
								}
								else
								{
									if (method_name.Equals("SocketInputBlock"))
									{
										return impl_delegate.Socketinputblock(args);
									}
									else
									{
										if (method_name.Equals("SocketCloseBlock"))
										{
											return impl_delegate.Socketcloseblock(args);
										}
										else
										{
											if (method_name.Equals("SocketAccept"))
											{
												CheckNumArgs(args, 1);
												return impl_delegate.Socketaccept(ToAwkString(args[0]));
											}
											else
											{
												if (method_name.Equals("SocketRead"))
												{
													CheckNumArgs(args, 1);
													return impl_delegate.Socketread(ToAwkString(args[0]));
												}
												else
												{
													if (method_name.Equals("SocketWrite"))
													{
														CheckNumArgs(args, 2);
														return impl_delegate.Socketwrite(ToAwkString(args[0]), ToAwkString(args[1]));
													}
													else
													{
														if (method_name.Equals("SocketFlush"))
														{
															CheckNumArgs(args, 1);
															return impl_delegate.Socketflush(ToAwkString(args[0]));
														}
														else
														{
															if (method_name.Equals("SocketClose"))
															{
																CheckNumArgs(args, 1);
																return impl_delegate.Socketclose(ToAwkString(args[0]));
															}
															else
															{
																throw new org.jawk.NotImplementedError(method_name);
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			
		}
	}

	/// <summary>
	/// Interface to the socket handling delegate which
	/// does all the work.
	/// </summary>
	/// <remarks>
	/// Interface to the socket handling delegate which
	/// does all the work.  The SocketExtension manager
	/// class delegates all concrete socket IO
	/// processing to an instance of this interface.
	/// </remarks>
	internal interface IIO_Style
	{
		// public class SocketExtension {AbstractExtension}
		//
		// INTERFACE TO DELEGATE
		//
		/// <summary>
		/// Sets up a server socket to listen for incomming
		/// connections.
		/// </summary>
		/// <remarks>
		/// Sets up a server socket to listen for incomming
		/// connections.  SocketRead on sockets accepted
		/// by ServerSocket return arbitrary-length Strings
		/// (bytes buffered by the input stream, converted
		/// to a string).
		/// </remarks>
		/// <param name="hostname">
		/// The hostname or IP address as a string.
		/// hostname can be null.
		/// </param>
		/// <param name="port">The port number.</param>
		/// <returns>A handle to a newly created serversocket.</returns>
		string Serversocket(string hostname, int port);

		/// <summary>
		/// Sets up a server socket to listen for incomming
		/// connections.
		/// </summary>
		/// <remarks>
		/// Sets up a server socket to listen for incomming
		/// connections.  SocketRead on sockets accepted
		/// by CServerSocket return strings which terminate
		/// by a newline, or text in the input buffer just
		/// prior to the closing of the socket.
		/// </remarks>
		/// <param name="hostname">
		/// The hostname or IP address as a string.
		/// hostname can be null.
		/// </param>
		/// <param name="port">The port number.</param>
		/// <returns>A handle to a newly created cserversocket.</returns>
		string Cserversocket(string hostname, int port);

		/// <summary>
		/// Create a Socket and connect it to a TCP socket
		/// endpoint.
		/// </summary>
		/// <remarks>
		/// Create a Socket and connect it to a TCP socket
		/// endpoint.  SocketRead on sockets returned
		/// by Socket return arbitrary-length Strings
		/// (bytes buffered by the input stream, converted
		/// to a string).
		/// </remarks>
		/// <param name="hostname">
		/// The hostname or IP address as a string.
		/// hostname can be null.
		/// </param>
		/// <param name="port">The port number.</param>
		/// <returns>A handle to a newly created socket.</returns>
		string Socket(string hostname, int port);

		/// <summary>
		/// Create a Socket and connect it to a TCP socket
		/// endpoint.
		/// </summary>
		/// <remarks>
		/// Create a Socket and connect it to a TCP socket
		/// endpoint.  SocketRead on sockets returned
		/// by Socket return strings which terminate
		/// by a newline, or text in the input buffer just
		/// prior to the closing of the socket.
		/// </remarks>
		/// <param name="hostname">
		/// The hostname or IP address as a string.
		/// hostname can be null.
		/// </param>
		/// <param name="port">The port number.</param>
		/// <returns>A handle to a newly created csocket.</returns>
		string Csocket(string hostname, int port);

		/// <summary>
		/// Blocks until a serversocket or cserversocket
		/// is ready to accept a connecting socket.
		/// </summary>
		/// <remarks>
		/// Blocks until a serversocket or cserversocket
		/// is ready to accept a connecting socket.
		/// </remarks>
		/// <param name="args">
		/// An array of
		/// serversocket or cserversocket handles
		/// and/or associative arrays whose keys
		/// are serversocket or cserversocket handles.
		/// The last argument can optionally be
		/// another block call for block chaining.
		/// </param>
		/// <returns>
		/// A block object conditioned
		/// to block on the acceptance of
		/// socket connections from any of
		/// the serversockets / cserversockets
		/// referred to by the handles passed
		/// in to the object array.
		/// </returns>
		org.jawk.jrt.BlockObject Socketacceptblock(object[] args);

		/// <summary>
		/// Blocks until a socket or csocket is ready
		/// to accept input (via SocketRead).
		/// </summary>
		/// <remarks>
		/// Blocks until a socket or csocket is ready
		/// to accept input (via SocketRead).
		/// </remarks>
		/// <param name="args">
		/// An array of
		/// socket or csocket handles and/or associative
		/// arrays whose keys are socket or csocket handles.
		/// The last argument can optionally be
		/// another block call for block chaining.
		/// </param>
		/// <returns>
		/// A block object conditioned
		/// to block on the availability of
		/// input from any of the sockets / csockets
		/// referred to by the handles passed
		/// in to the object array.
		/// </returns>
		org.jawk.jrt.BlockObject Socketinputblock(object[] args);

		/// <summary>
		/// Blocks until a serversocket, cserversocket,
		/// socket, or csocket has been closed on the
		/// remote end.
		/// </summary>
		/// <remarks>
		/// Blocks until a serversocket, cserversocket,
		/// socket, or csocket has been closed on the
		/// remote end.
		/// </remarks>
		/// <param name="args">
		/// An array of
		/// serversocket, cserversocket, socket, or csocket
		/// handles and/or associative
		/// arrays whose keys are serversocket, cserversocket,
		/// socket, or csocket handles.
		/// The last argument can optionally be
		/// another block call for block chaining.
		/// </param>
		/// <returns>
		/// A block object conditioned
		/// to block until any of the sockets /
		/// csockets / serversockets / cserversockets
		/// in to the object array have closed.
		/// </returns>
		org.jawk.jrt.BlockObject Socketcloseblock(object[] args);

		/// <summary>
		/// Accepts a socket from a serversocket or
		/// a cserversocket.
		/// </summary>
		/// <remarks>
		/// Accepts a socket from a serversocket or
		/// a cserversocket.  The operation will
		/// block if there is no socket to accept.
		/// </remarks>
		/// <param name="handle">
		/// A string handle to a serversocket
		/// or cserversocket.
		/// </param>
		/// <returns>
		/// A handle to a socket or csocket that
		/// has connected to the serversocket / cserversocket
		/// referred to by the handle argument.
		/// </returns>
		string Socketaccept(string handle);

		/// <summary>
		/// Reads input from the input stream of a socket
		/// or a csocket.
		/// </summary>
		/// <remarks>
		/// Reads input from the input stream of a socket
		/// or a csocket.  For a socket, the input length
		/// is arbitrary.  For a csocket, the input
		/// length is bounded by a newline or upon
		/// termination of the socket.
		/// The operation will block if there is no input
		/// on the socket.
		/// </remarks>
		/// <param name="handle">
		/// A string handle to a socket
		/// or csocket.
		/// </param>
		/// <returns>
		/// A block of byte input from a socket
		/// (converted to a string), or a line of
		/// string input from a csocket bounded by
		/// a newline in the stream or upon the closing
		/// of the csocket.
		/// </returns>
		string Socketread(string handle);

		/// <summary>Writes data to the socket or csocket.</summary>
		/// <remarks>
		/// Writes data to the socket or csocket.
		/// For a socket, the string is converted
		/// to bytes (via java.lang.String.getBytes()),
		/// and the bytes are sent to the underlying
		/// socket's output stream.
		/// For a csocket, println() is called on the
		/// underlying socket's PrintStream.
		/// </remarks>
		/// <param name="handle">
		/// A string handle to a socket
		/// or csocket.
		/// </param>
		/// <param name="buf">
		/// The string containing the
		/// bytes to write.  SocketWrite writes
		/// the contents of the resulting buf.getBytes()
		/// call to the socket.
		/// </param>
		/// <param name="handle">
		/// A String handle to a socket
		/// or csocket.
		/// </param>
		/// <param name="buf">
		/// A string containing a block of
		/// bytes to write to a socket (via
		/// java.lang.String.getBytes()) if handle
		/// refers to a socket.  If handle refers
		/// to a csocket, the line of text to write
		/// via PrintStream.println(String).
		/// </param>
		/// <returns>
		/// 1 upon a successful write,
		/// 0 upon an IO exception/error.
		/// </returns>
		int Socketwrite(string handle, string buf);

		/// <summary>Flushes the output stream of a socket or csocket.</summary>
		/// <remarks>Flushes the output stream of a socket or csocket.</remarks>
		/// <param name="handle">
		/// A string handle to a socket
		/// or csocket.
		/// </param>
		/// <returns>
		/// 1 upon a successful flush operation,
		/// 0 upon an IO exception/error.
		/// </returns>
		int Socketflush(string handle);

		/// <summary>
		/// Closes the socket/csocket on the local end,
		/// or a serversocket/cserversocket.
		/// </summary>
		/// <remarks>
		/// Closes the socket/csocket on the local end,
		/// or a serversocket/cserversocket.
		/// Can be called in response to a SocketCloseBlock
		/// event, or to force a socket/csocket connection to
		/// terminate.
		/// </remarks>
		/// <param name="handle">
		/// A string handle to a socket,
		/// csocket, serversocket, or cserversocket.
		/// </param>
		/// <returns>
		/// 1 upon a successful close operation,
		/// 0 upon an IO exception/error.
		/// </returns>
		int Socketclose(string handle);
	}

	/// <summary>A view of two maps as one map.</summary>
	/// <remarks>A view of two maps as one map.</remarks>
	internal class MapUnion<K, V> : Dictionary<K, V>
	{
		private System.Collections.Generic.IDictionary<K, V> m1;

		private System.Collections.Generic.IDictionary<K, V> m2;

		internal MapUnion(System.Collections.Generic.IDictionary<K, V> m1, System.Collections.Generic.IDictionary
			<K, V> m2)
		{
			this.m1 = m1;
			this.m2 = m2;
		}

		public System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair <K, V>> EntrySet()
		{
			// build the entry set
			System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> entry_set = new List<KeyValuePair<K, V>>();
			System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> s1 = m1;
			System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> s2 = m2;
			foreach (System.Collections.Generic.KeyValuePair<K, V> me in s1)
			{
				entry_set.Add(me);
			}
			foreach (System.Collections.Generic.KeyValuePair<K, V> me in s2)
			{
				entry_set.Add(me);
			}
			return entry_set;
		}
	}

	internal class Threaded_IO_Style : org.jawk.ext.IIO_Style
	{
		private string last_err = null;

		/// <summary>
		/// Map of "Socket"/"CSocket" handles to
		/// the objects which perform the actual
		/// read and block operations.
		/// </summary>
		/// <remarks>
		/// Map of "Socket"/"CSocket" handles to
		/// the objects which perform the actual
		/// read and block operations.
		/// <p>
		/// <strong>Note:</strong>
		/// "consumers" originally was of type
		/// Map<String,Consumer>, but changed to ...,Closeable.
		/// (Likewise, "accepters" was originally ...,Accepter,
		/// but then changed to ...,Closeable.)
		/// Why?  Because MapUnion could not infer that "Consumer"
		/// nor "Accepter" were extensions of "Blockable".
		/// MapUnion originally accepted 3 generic parameters:
		/// K, V1 extends Blockable, and V2 extends Blockable.
		/// And, close_blocker's BulkBlockObject Map parameter was:
		/// new MapUnion<String,Accepter,Consumer>(accepters,consumers).
		/// But, it wouldn't compile.
		/// The resulting warning/error messages stated that
		/// "capture #XXX of ? extends Blockable" does not
		/// match "? extends Blockable".  I believe the error
		/// results from Blockable being compiled against
		/// Java 1.5.x and extensions being developed against
		/// Java 1.6.x, and that they don't grok one another
		/// in this scenario.
		/// We, then, decided to assign its lowest common
		/// subclass, "Closeable", and typecast when we need
		/// specific "Accepter" and "Consumer" functionality.
		/// This resolved the issue while losing some
		/// compile-time type safety.
		/// </remarks>
		private readonly System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable> consumers = new System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable>();

		/// <summary>
		/// Map of "ServerSocket"/"CServerSocket" handles
		/// to the objects which perform the actual
		/// socket accept operation.
		/// </summary>
		/// <remarks>
		/// Map of "ServerSocket"/"CServerSocket" handles
		/// to the objects which perform the actual
		/// socket accept operation.
		/// <p>
		/// <strong>Note:</strong>
		/// See lengthy diatribe above for "consumers".
		/// The same applies for "accepters"'s generic
		/// type choice for values of the Map.
		/// </remarks>
		private readonly System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable> accepters = new System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable>();

		private readonly org.jawk.jrt.IVariableManager vm;

		private readonly org.jawk.jrt.BulkBlockObject accept_blocker;

		private readonly org.jawk.jrt.BulkBlockObject input_blocker;

		private readonly org.jawk.jrt.BulkBlockObject close_blocker;

		internal Threaded_IO_Style(org.jawk.jrt.IVariableManager vm)
		{
			accept_handle_validator = new _IBlockHandleValidator_759(this);
			input_handle_validator = new _IBlockHandleValidator_772(this);
			close_handle_validator = new _IBlockHandleValidator_785(this);
			//assert vm != null;
			this.vm = vm;
			accept_blocker = new org.jawk.jrt.BulkBlockObject("SocketAccept", accepters, vm);
			input_blocker = new org.jawk.jrt.BulkBlockObject("SocketInput", consumers, vm);
			close_blocker = new org.jawk.jrt.BulkBlockObject("SocketClose", new org.jawk.ext.MapUnion<string, org.jawk.jrt.ICloseable>(accepters, consumers), vm);
		}

		public string Serversocket(string hostname, int port)
		{
			try
			{
                
                TcpListener ss = null;

				if (hostname == null)
				{
                    ss = new TcpListener(System.Net.IPAddress.Any, port);                 
				}
				else
				{
					// 0 = default backlog
                    System.Net.IPAddress[] tab = System.Net.Dns.GetHostAddresses(hostname);

                    System.Net.IPAddress address = System.Net.IPAddress.Any;
                    if(tab!=null && tab.Length>0)
                    {
                        address = tab[0];
                    }
                    ss = new TcpListener(address, port);  
				}
				string handle = CreateHandle(ss);
				//ssockets.put(handle, ss);
				org.jawk.ext.Threaded_IO_Style.Accepter accepter_thread = new org.jawk.ext.Threaded_IO_Style.Accepter
					(this, handle, ss);
				accepters[handle] = accepter_thread;
				accepter_thread.Start();
				return handle;
			}
			catch (System.IO.IOException ioe)
			{
                Console.Error.WriteLine(ioe.ToString());
				last_err = ioe.ToString();
				return string.Empty;
			}
		}

		public string Cserversocket(string hostname, int port)
		{
			try
			{
				TcpListener ss;
				if (hostname == null)
				{
					ss = new TcpListener(System.Net.IPAddress.Any,port);
				}
				else
				{
					// 0 = default backlog
                    System.Net.IPAddress[] tab = System.Net.Dns.GetHostAddresses(hostname);

                    System.Net.IPAddress address = System.Net.IPAddress.Any;
                    if (tab != null && tab.Length > 0)
                    {
                        address = tab[0];
                    }
                    ss = new TcpListener(address, port); 
				}
				string handle = CreateHandle(ss);
				//ssockets.put(handle, ss);
				org.jawk.ext.Threaded_IO_Style.Accepter accepter_thread = new org.jawk.ext.Threaded_IO_Style.CAccepter
					(this, handle, ss);
				accepters[handle] = accepter_thread;
				accepter_thread.Start();
				return handle;
			}
			catch (System.IO.IOException ioe)
			{
                Console.Error.WriteLine(ioe.ToString());
				last_err = ioe.ToString();
				return string.Empty;
			}
		}

		public string Socket(string hostname, int port)
		{
			// create the socket
			try
			{
				TcpClient socket = new TcpClient(hostname, port);
				string handle = CreateHandle(socket);
				//sockets.put(handle, socket);
				// start the reader
				org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.ByteConsumer
					(this, handle, socket);
				consumers[handle] = reader_thread;
				reader_thread.Start();
				return handle;
			}
			catch (System.IO.IOException ioe)
			{
                Console.Error.WriteLine(ioe.ToString());
				last_err = ioe.ToString();
				return string.Empty;
			}
		}

		public string Csocket(string hostname, int port)
		{
			try
			{
				// create the socket
				TcpClient socket = new TcpClient(hostname, port);
				string handle = CreateHandle(socket);
				//sockets.put(handle, socket);
				// start the reader
				org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.CharacterConsumer
					(this, handle, socket);
				consumers[handle] = reader_thread;
				reader_thread.Start();
				return handle;
			}
			catch (System.IO.IOException ioe)
			{
				Console.Error.WriteLine(ioe.ToString());
				last_err = ioe.ToString();
				return string.Empty;
			}
		}

		private int socket_idx = 0;

		private int ssocket_idx = 0;

		private string CreateHandle(TcpListener socket)
		{
            System.Net.IPEndPoint endPoint = socket.LocalEndpoint as System.Net.IPEndPoint;

            if (endPoint != null)
            {
                return "Socket:" + endPoint.Address.ToString() + ":" + endPoint.Port + "/" + (++ssocket_idx);
            }
            else
            {
                return "Socket:" + socket.LocalEndpoint.Serialize().ToString() + "/" + (++ssocket_idx);
            }
		}

        private string CreateHandle(TcpClient socket)
        {
            System.Net.IPEndPoint endPoint = socket.Client.LocalEndPoint as System.Net.IPEndPoint;

            if (endPoint != null)
            {
                return "Socket:" + endPoint.Address.ToString() + ":" + endPoint.Port + "/" + (++socket_idx);
            }
            else
            {
                return "Socket:" + socket.Client.LocalEndPoint.Serialize().ToString() + "/" + (++socket_idx);
            }
        }

		private sealed class _IBlockHandleValidator_759 : org.jawk.jrt.IBlockHandleValidator
		{
			public _IBlockHandleValidator_759(Threaded_IO_Style _enclosing)
			{
				this._enclosing = _enclosing;
			}

			//////////////////////////////////////////////////////////////////
			//////////////////////////////////////////////////////////////////
			//////////////////////////////////////////////////////////////////
			// to satisfy the BlockHandleValidator interface
			public string IsBlockHandleValid(string handle)
			{
				org.jawk.jrt.ICloseable closeable = null;
                if(this._enclosing.accepters.ContainsKey(handle))
                {
                    closeable = this._enclosing.accepters[handle];
                }
				if (closeable == null)
				{
					return "Invalid ServerSocket handle.";
				}
				if (closeable.IsClosed())
				{
					return "ServerSocket is closed.";
				}
				else
				{
					return null;
				}
			}

			private readonly Threaded_IO_Style _enclosing;
		}

		private readonly org.jawk.jrt.IBlockHandleValidator accept_handle_validator;

		private sealed class _IBlockHandleValidator_772 : org.jawk.jrt.IBlockHandleValidator
		{
			public _IBlockHandleValidator_772(Threaded_IO_Style _enclosing)
			{
				this._enclosing = _enclosing;
			}

			// valid
			// to satisfy the BlockHandleValidator interface
			public string IsBlockHandleValid(string handle)
			{
				org.jawk.jrt.ICloseable closeable = null;
                if (this._enclosing.consumers.ContainsKey(handle))
                {
                    closeable = this._enclosing.consumers[handle];
                }
				if (closeable == null)
				{
					return "Invalid socket handle.  (Could have already been closed?)";
				}
				if (closeable.IsClosed())
				{
					return "Socket is closed.";
				}
				else
				{
					return null;
				}
			}

			private readonly Threaded_IO_Style _enclosing;
		}

		private readonly org.jawk.jrt.IBlockHandleValidator input_handle_validator;

		private sealed class _IBlockHandleValidator_785 : org.jawk.jrt.IBlockHandleValidator
		{
			public _IBlockHandleValidator_785(Threaded_IO_Style _enclosing)
			{
				this._enclosing = _enclosing;
			}

			// valid
			// to satisfy the BlockHandleValidator interface
			public string IsBlockHandleValid(string handle)
			{
				org.jawk.jrt.ICloseable closeable = null;
                if(this._enclosing.accepters.ContainsKey(handle))
                {
                    closeable = this._enclosing.accepters[handle];
                }
                if (closeable == null && this._enclosing.consumers.ContainsKey(handle))
				{
					closeable = this._enclosing.consumers[handle];
				}
				if (closeable == null)
				{
					return "Invalid socket handle.  (Could have already been closed?)";
				}
				if (closeable.IsClosed())
				{
					return "Socket is already closed.";
				}
				else
				{
					return null;
				}
			}

			private readonly Threaded_IO_Style _enclosing;
		}

		private readonly org.jawk.jrt.IBlockHandleValidator close_handle_validator;

		// valid
		public org.jawk.jrt.BlockObject Socketacceptblock(object[] args)
		{
			return accept_blocker.PopulateHandleSet(args, vm, accept_handle_validator);
		}

		public org.jawk.jrt.BlockObject Socketinputblock(object[] args)
		{
			return input_blocker.PopulateHandleSet(args, vm, input_handle_validator);
		}

		public org.jawk.jrt.BlockObject Socketcloseblock(object[] args)
		{
			return close_blocker.PopulateHandleSet(args, vm, close_handle_validator);
		}

		public string Socketaccept(string handle)
		{
			try
			{
				org.jawk.ext.Threaded_IO_Style.Accepter accepter = null;
                if(accepters.ContainsKey(handle))
                {
                    accepter = (org.jawk.ext.Threaded_IO_Style.Accepter)accepters[handle];
                }
				if (accepter == null)
				{
					throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid server socket handle : "
						 + handle);
				}
				// it's "as if" accept_blocker is querying whether to block or not
				if (accepter.WillBlock(accept_blocker) && accepter.IsClosed())
				{
					last_err = "Server closed.";
					return string.Empty;
				}
				return accepter.GetSocket();
			}
			catch (System.IO.IOException ioe)
			{
                Console.Error.WriteLine(ioe.ToString());
				throw new System.Exception("Error occurred during creation of accepted socket.");
			}
            catch (System.Exception ie)
            {
                Console.Error.WriteLine(ie.ToString());
                throw new System.Exception("A queue operation cannot be interrupted.");
            }
		}

		public string Socketread(string handle)
		{
			try
			{
				org.jawk.jrt.IConsumer consumer = null;
                if(consumers.ContainsKey(handle))
                {
                    consumer = (org.jawk.jrt.IConsumer)consumers[handle];
                }
				if (consumer == null)
				{
					throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle
						);
				}
				// it's "as if" input_blocker is querying whether to block or not
				if (consumer.WillBlock(input_blocker) && consumer.IsClosed())
				{
					last_err = "No more input.";
					return string.Empty;
				}
				return consumer.GetInput();
			}
			catch (System.Exception ie)
			{
				Console.Error.WriteLine(ie);
				throw new System.Exception("A queue operation cannot be interrupted.");
			}
		}

		public int Socketwrite(string handle, string buf)
		{
			org.jawk.jrt.IConsumer consumer = null;
            if(consumers.ContainsKey(handle))
            {
                consumer = (org.jawk.jrt.IConsumer)consumers[handle];
            }
			if (consumer == null)
			{
				throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle
					);
			}
			return consumer.Write(buf);
		}

		public int Socketflush(string handle)
		{
			org.jawk.jrt.IConsumer consumer = null;
            if(consumers.ContainsKey(handle))
            {
                consumer = (org.jawk.jrt.IConsumer)consumers[handle];
            }
			if (consumer == null)
			{
				throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle
					);
			}
			return consumer.Flush();
		}

		public int Socketclose(string handle)
		{

            org.jawk.jrt.ICloseable t = null;

            if (consumers.ContainsKey(handle))
            {
                t = consumers[handle];
                consumers.Remove(handle);
            }

		    if (t == null && accepters.ContainsKey(handle))
			{
                t = accepters[handle];
                accepters.Remove(handle);
			}

			if (t == null)
			{
				throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid [server]socket handle : " + handle);
			}
			int retval;
			try
			{
				t.Close();
				retval = 1;
			}
			catch (System.IO.IOException ioe)
			{
				Console.Error.WriteLine(ioe);
				retval = 0;
			}
			// interrupt the thread
			t.Interrupt();
			// join on the thread
			try
			{
				t.Join();
			}
			catch (System.Exception)
			{
				throw new System.Exception("A socket close() cannot be interrupted.");
			}
			return retval;
		}

		private class Accepter : IThread, org.jawk.jrt.ICloseable
		{
			private string handle;

			private TcpListener ssocket;

			protected java.util.BlockingQueue<TcpClient> queue = new java.util.BlockingQueue
				<TcpClient>(1);

			//////////////////////////////////////////////////////////////////
			//////////////////////////////////////////////////////////////////
			//////////////////////////////////////////////////////////////////
			// only 1 slot
			//private BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
			public virtual bool WillBlock(org.jawk.jrt.BlockObject bo)
			{
				return this.queue.Count == 0;
			}

			/// <exception cref="System.IO.IOException"></exception>
			public Accepter(Threaded_IO_Style _enclosing, string handle, TcpListener ssocket)
			{
				this._enclosing = _enclosing;
				this.handle = handle;
				//ssocket = ssockets.get(handle);
				this.ssocket = ssocket;

                mThread = new Thread(Run);
			}

			//assert ssocket != null;
			public void Run()
			{
				if (Thread.CurrentThread != mThread)
				{
					throw new System.Exception("Invalid thread access : " + Thread.CurrentThread);
				}
				try
				{
					TcpClient socket;
					while (true)
					{
                        socket = this.ssocket.AcceptTcpClient();
						this.queue.Put(socket);
						lock (this._enclosing.accept_blocker)
						{
                            Monitor.Pulse(this._enclosing.accept_blocker);
						}
					}
				}				
				catch (System.Net.Sockets.SocketException se)
				{
                    Console.Error.WriteLine(se);
				}
				catch (System.IO.IOException ioe)
				{
					// no big deal
					// assume we should just shutdown now
					Console.Error.WriteLine(ioe);
				}
                catch (System.Exception ie)
                {
                    Console.Error.WriteLine(ie);
                    throw new System.Exception("A queue operation cannot be interrupted.");
                }
				// no big deal
				lock (this._enclosing.close_blocker)
				{
                    Monitor.Pulse(this._enclosing.close_blocker);
				}
			}

			// can be overridden
			/// <exception cref="System.IO.IOException"></exception>
			/// <exception cref="System.Exception"></exception>
			public virtual string GetSocket()
			{
				TcpClient socket = this.queue.Take();
				// ... same as socket() method ...
				string handle = this._enclosing.CreateHandle(socket);
				// start the reader
				org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.ByteConsumer
					(this._enclosing, handle, socket);
				reader_thread.Start();
				this._enclosing.consumers[handle] = reader_thread;
				return handle;
			}

			public virtual bool IsClosed()
			{
				return !mThread.IsAlive;
			}

			/// <exception cref="System.IO.IOException"></exception>
			public void Close()
			{
				this.ssocket.Stop();
			}

			private readonly Threaded_IO_Style _enclosing;

            #region IThread Members

            private Thread mThread;
            public void Start()
            {
                mThread.Start();
            }

            public void SetDaemon(bool b)
            {
                mThread.IsBackground = b;
            }

            #endregion

            #region IJoinable Members

            public void Join()
            {
                mThread.Join();
            }

            public void Interrupt()
            {
                mThread.Interrupt();
            }

            #endregion
        }

		private sealed class CAccepter : org.jawk.ext.Threaded_IO_Style.Accepter
		{
			/// <exception cref="System.IO.IOException"></exception>
			public CAccepter(Threaded_IO_Style _enclosing, string handle, TcpListener
				 ssocket) : base(_enclosing, handle, ssocket)
			{
				this._enclosing = _enclosing;
			}

			/// <exception cref="System.IO.IOException"></exception>
			/// <exception cref="System.Exception"></exception>
			public sealed override string GetSocket()
			{
				TcpClient socket = this.queue.Take();
				// ... same as socket() method ...
				string handle = this._enclosing.CreateHandle(socket);
				// start the reader
				org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.CharacterConsumer
					(this._enclosing, handle, socket);
				reader_thread.Start();
				this._enclosing.consumers[handle] = reader_thread;
				return handle;
			}

			private readonly Threaded_IO_Style _enclosing;
		}

		

		

		private abstract class AbstractConsumer<T> : IThread, org.jawk.jrt.IConsumer
		{
			private readonly string handle;

			protected readonly TcpClient socket;

			protected readonly System.IO.TextWriter ps;

			private int state = org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE;

			protected java.util.BlockingQueue<T> queue = new java.util.BlockingQueue
				<T>(1);

			// only 1 slot
			public bool WillBlock(org.jawk.jrt.BlockObject bo)
			{
				if (bo == this._enclosing.input_blocker)
				{
					return this.queue.Count == 0;
				}
				else
				{
					if (bo == this._enclosing.close_blocker)
					{
						return this.state == org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE;
					}
					else
					{
						throw new System.Exception("Unknown block object : " + bo.GetNotifierTag());
					}
				}
			}

			/// <exception cref="System.IO.IOException"></exception>
			protected AbstractConsumer(Threaded_IO_Style _enclosing, string handle, TcpClient
				 socket)
			{
				this._enclosing = _enclosing;
				this.handle = handle;
				//socket = sockets.get(handle);
				this.socket = socket;
				//assert socket != null;
				this.ps = new System.IO.StreamWriter(socket.GetStream());


                mThread = new Thread(new ThreadStart(Run));
			}

			/// <exception cref="System.IO.IOException"></exception>
			protected abstract T ReadFromSocket();

			public void Run()
			{
				if (Thread.CurrentThread != this.mThread)
				{
					throw new System.Exception("Invalid thread access : " + Thread.CurrentThread);
				}
				try
				{
					T input;
					while ((input = this.ReadFromSocket()) != null)
					{
						this.queue.Put(input);
						lock (this._enclosing.input_blocker)
						{
                            Monitor.Pulse(this._enclosing.input_blocker);
						}
					}
				}
				catch (System.Net.Sockets.SocketException se)
				{
                    Console.Error.WriteLine(se);
				}
				catch (System.IO.IOException ioe)
				{
					// no big deal
					// assume we should just shutdown now
					Console.Error.WriteLine(ioe);
				}
                catch (System.Exception ie)
                {
                    Console.Error.WriteLine(ie);
                    throw new System.Exception("A queue operation cannot be interrupted.");
                }
                // no big deal
				lock (this._enclosing.close_blocker)
				{
					if (this.state == org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE)
					{
						this.state = org.jawk.ext.Threaded_IO_Style.CLOSE_PENDING_STATE;
                        Monitor.Pulse(this._enclosing.close_blocker);
					}
				}
			}

			/// <exception cref="System.Exception"></exception>
			protected abstract string ReadFromQueue();

			/// <exception cref="System.Exception"></exception>
			public string GetInput()
			{
				//assert state != CLOSED_STATE;	// active or close_pending
				string str = this.ReadFromQueue();
				if (this.queue.Count == 0 && this.state
					 == org.jawk.ext.Threaded_IO_Style.CLOSE_PENDING_STATE)
				{
					lock (this._enclosing.close_blocker)
					{
						// could be either ACTIVE or CLOSE_PENDING states
						//assert state != CLOSED_STATE;
                        Monitor.Pulse(this._enclosing.close_blocker);
					}
				}
				return str;
			}

			// write is defined in subclasses
			public int Flush()
			{
				this.ps.Flush();
				return 1;
			}

			public bool IsClosed()
			{
				return this.state == org.jawk.ext.Threaded_IO_Style.CLOSED_STATE;
			}

			/// <exception cref="System.IO.IOException"></exception>
			public void Close()
			{
				this.socket.Close();
			}

			public abstract int Write(string arg1);

			private readonly Threaded_IO_Style _enclosing;

            #region IThread Members

            private Thread mThread = null;
            public void Start()
            {
                mThread.Start();
            }

            public void SetDaemon(bool b)
            {
                mThread.IsBackground = b;
            }
            #endregion

            #region IJoinable Members

            public void Join()
            {
                mThread.Join();
            }

            public void Interrupt()
            {
                mThread.Interrupt();
            }

            #endregion
        }

		private const int ACTIVE_STATE = 1;

		private const int CLOSE_PENDING_STATE = 2;

		private const int CLOSED_STATE = 3;

		private sealed class CharacterConsumer : org.jawk.ext.Threaded_IO_Style.AbstractConsumer
			<string>
		{
			private readonly System.IO.StreamReader br;

			/// <exception cref="System.IO.IOException"></exception>
			public CharacterConsumer(Threaded_IO_Style _enclosing, string handle, TcpClient
				 socket) : base(_enclosing, handle, socket)
			{
				this._enclosing = _enclosing;
				// private abstract class AbstractConsumer<T> {Thread} [Consumer]
				// constructs socket (protected field in AbstractConsumer)
				this.br = new StreamReader(socket.GetStream());
			}

            ~CharacterConsumer()
            {
                this.br.Dispose();
            }

			/// <exception cref="System.IO.IOException"></exception>
			protected sealed override string ReadFromSocket()
			{
				return this.br.ReadLine();
			}

			/// <exception cref="System.Exception"></exception>
			protected sealed override string ReadFromQueue()
			{
				return this.queue.Take();
			}

			public sealed override int Write(string buf)
			{
				this.ps.WriteLine(buf);
				return 1;
			}

			private readonly Threaded_IO_Style _enclosing;
		}

		private sealed class ByteConsumer : org.jawk.ext.Threaded_IO_Style.AbstractConsumer
			<int?>
		{
			private readonly Stream bis;

			private readonly byte[] buf = new byte[4096];

			/// <exception cref="System.IO.IOException"></exception>
			public ByteConsumer(Threaded_IO_Style _enclosing, string handle, TcpClient
                 socket)
                : base(_enclosing,handle, socket)
			{
				this._enclosing = _enclosing;
				// constructs socket (protected field in AbstractConsumer)
				this.bis = socket.GetStream();
			}

			/// <exception cref="System.IO.IOException"></exception>
			protected sealed override int? ReadFromSocket()
			{
				int len = this.bis.Read(this.buf, 0, this.buf.Length);
				if (len < 0)
				{
					return null;
				}
				else
				{
					return len;
				}
			}

			/// <exception cref="System.Exception"></exception>
			protected sealed override string ReadFromQueue()
			{
				int len = this.queue.Take().GetValueOrDefault(0);

                string str = System.Text.Encoding.UTF8.GetString(this.buf,0,len);
				return str;
			}

			public sealed override int Write(string buf)
			{
				try
				{
					byte[] b = System.Text.Encoding.UTF8.GetBytes(buf);
					this.ps.Write(b);
					return 1;
				}
				catch (System.IO.IOException ioe)
				{
					Console.Error.WriteLine(ioe);
					this._enclosing.last_err = ioe.ToString();
					return 0;
				}
			}

			private readonly Threaded_IO_Style _enclosing;
		}
	}
}
